package com.gitee.feizns.explore.data_structure.queue;


import java.util.function.Consumer;

/**
 * @author feizns
 * @since 2019/10/30
 */
public class LoopQueue<E> implements Queue<E> {

    private Object[] arr;

    private int head = -1;

    private int tail = 0;

    public LoopQueue(int capacity) {
        this.arr = new Object[capacity];
    }

    @Override
    public int size() {
        if ( isFull() )
            return arr.length;
        if ( isEmpty() )
            return 0;
        return ((arr.length + tail) - head) % arr.length;
    }

    @Override
    public boolean enqueue(E e) {
        if ( !isFull() ) {
            arr[tail] = e;
            if ( head == -1 )
                head = tail;
            tail = next(tail);
            return true;
        }
        return false;
    }

    @Override
    public E dequeue() {
        if ( isEmpty() )
            return null;
        E ret = (E) arr[head];
        head = next(head);
        if ( head == tail )
            reset();
        return ret;
    }

    @Override
    public E peek() {
        if ( isEmpty() )
            return null;
        return (E) arr[head];
    }

    @Override
    public boolean isFull() {
        return tail == head;
    }

    @Override
    public boolean isEmpty() {
        return head == -1;
    }

    @Override
    public void forEach(Consumer<E> t) {
        for (int i = 0, index = head; i < size(); i++, index = next(index)) {
            t.accept((E) arr[index]);
        }
    }

    private int next(int curt) {
        return (curt + 1) % arr.length;
    }

    private void reset() {
        head = -1;
        tail = 0;
    }

    @Override
    public String toString() {
        StringBuilder ret = new StringBuilder("[");
        forEach(t -> {
            ret.append(t + ",");
        });
        if ( ret.length() > 1 )
            ret.setLength(ret.length() - 1);
        ret.append("]");
        return ret.toString();
    }

    public static void main(String[] args) {
        Queue<String> queue = new LoopQueue<>(3);
        System.out.println(queue.enqueue("1") + " enter 1");
        System.out.println(queue.enqueue("2") + " enter 2");
        System.out.println(queue.enqueue("3") + " enter 3");
        System.out.println(queue);
        System.out.println(queue.enqueue("4") + " enter 3");
        System.out.println(queue);
        System.out.println(queue.dequeue() + " deq");
        System.out.println(queue.dequeue() + " deq");
        System.out.println(queue);
        System.out.println(queue.dequeue() + " deq");
        System.out.println(queue.dequeue() + " deq");
        System.out.println(queue.dequeue() + " deq");
        System.out.println(queue);
//        queue.dequeue();
//        queue.dequeue();
//        System.out.println(queue);
//        queue.enqueue("4");
//        System.out.println(queue);
    }

}
